/* 
 * File:   Character.cpp
 * Author: paula
 * 
 * Created on 8 de septiembre de 2014, 23:26
 */

#include "Character.h"

Character::Character() {
}

Character::Character(const Character& orig) {
}

Character::Character(ObjFactory *objFactory, int x, int y, int id) {

    this->myLogFile->getInstance(MY_LOG_MODE);
    this->objFactory = objFactory;
    this->windowUnitWidth = this->objFactory->getUnitWidth();
    this->windowUnitHeight = this->objFactory->getUnitHeight();
    switch (id) {
        case 1:
            this->objWidth = CHARACTER_1_WIDTH * PRINCIPAL_SCALE;
            this->objHeight = CHARACTER_1_HEIGHT * PRINCIPAL_SCALE;
            break;
        case 2:
            this->objWidth = CHARACTER_2_WIDTH * PRINCIPAL_SCALE;
            this->objHeight = CHARACTER_2_HEIGHT * PRINCIPAL_SCALE;
            break;
        case 3:
            this->objWidth = CHARACTER_3_WIDTH * PRINCIPAL_SCALE;
            this->objHeight = CHARACTER_3_HEIGHT * PRINCIPAL_SCALE;
            break;
        case 4:
            this->objWidth = CHARACTER_4_WIDTH * PRINCIPAL_SCALE;
            this->objHeight = CHARACTER_4_HEIGHT * PRINCIPAL_SCALE;
            break;
        case 11:
            //tengo que agregar bien el tamaño del malo
            this->objWidth = CHARACTER_4_WIDTH * PRINCIPAL_SCALE;
            this->objHeight = CHARACTER_4_HEIGHT * PRINCIPAL_SCALE;
            break;
    }
    //    cout<<"Posicion del resucitado en CHARACTER(x,y): "<<x<<y<<endl; 
    Dot *dotito = new Dot(x, y, objWidth, objHeight);
    string lineToLog = "";

    //  Comentamos esto porque si el personaje pasa por el overlap no se nota que nace donde murio.
    //    //si el personaje se superpone con los bordes del mapa, cambio su posicion.
    //    if (this->characterOverlap(x, y)) {
    //        dotito->setPos(this->windowUnitWidth / 2, this->windowUnitHeight / 2);
    //        lineToLog = "[1] El personaje choca con los bordes del  mapa  en x: " + to_string(x) + ", y:" + to_string(y) + ". Cambia su posicion al centro del mapa. \n";
    //        myLogFile->writeInLog(1, lineToLog);
    //        cout<<"overlap me cambio la posicion"<<endl;
    //    }defaultValues

    //Si el personaje esta fuera de los limites del mapa, cambio su posicion.
    if ((x < 0) || (y < 0) || (x >this->windowUnitWidth) || (y> this->windowUnitHeight)) {
        lineToLog = "[1] El personaje esta fuera de los limites del mapa x: " + to_string(x) + ", y:" + to_string(y) + ". Cambia su posicion al centro del mapa. \n";
        myLogFile->writeInLog(1, lineToLog);
        dotito->setPos(this->windowUnitWidth / 2, this->windowUnitHeight / 2);
    }

    this->dot = dotito;
    Object *object = objFactory->getCharacter(this->dot->dotPixelsToWorld(), this->dot->sizeDotPixelsToWorld());
    this->object = object;

    b2Vec2 vecc(object->getPosition().x, object->getPosition().y);
    this->posInitial = vecc;

    this->directionRight = true;
    this->counterReborn = 0;
    this->counterKneel = 1;
    this->counterJump = 1;
    this->counterWait = 9;
    this->beginning = true;
    this->delayWalk = 10;
    this->delay = 20;
    this->canFallLeft = true;
    this->canFallRight = true;
    this->canJumpLeft = true;
    this->canJumpRight = true;
    this->jumping = false;
    this->kneeling = false;
    this->walking = false;
    this->fallingDown = false;
    this->wasJumping = false;
    this->dead = false;
    this->dying = false;
    //    this->nd = 0;
    this->lastPosY = 0;
    this->currentPosY = 0;
    this->lastVelY = 0;
    this->currentVelY = 0;

    this->constFall = 2.7f;
    this->constJump = 2.7f;

    this->score = INITIAL_SCORE;
    this->lifes = INITIAL_LIFES;

    // inicializo data 
    struct ObjectInit obj;
    obj.x = x;
    obj.y = y;
    obj.stateCharacter = this->getState();
    obj.estatico = false;
    obj.event.pressed = 'Z'; // inicial defaul
    obj.objectId = VACIO;
    obj.lifes = this->lifes;
    obj.score = this->score;
    obj.level = 0;
    obj.idCharacter = id;
    this->data = obj;

    this->lastState = 0;

    this->equals = false;
    this->wasJumping = false;

    this->velocityWalkLeft = 0.0;
    this->velocityWalkRight = 0.0;
    this->deltaVelocity = 0.5;
    this->maxVelocityStandard = 4.0;
    this->maxVelocityPlus = 11.0;
    this->maxVelocity = this->maxVelocityStandard;
    this->walkingFaster = false;
    this->plusVelTime = 15; //seconds

    if (this->data.idCharacter < 10) {
        this->object->getBody()->SetUserData((void*) IS_CHARACTER);
    }

    //SHOOT
    SnowGun *weapon = new SnowGun(objFactory);
    this->weapon = weapon;

    this->avisarleATodos = false;
    this->contAvisarleATodos = 1;
}

void Character::restartPlayer() {
    if (this->isWatching()) {
        this->getBody()->SetType(b2_dynamicBody);
        this->watching = false;
    }
    this->score = INITIAL_SCORE;
    this->lifes = INITIAL_LIFES;
    this->changeToPosInitial();
    this->wait();
}

bool Character::characterOverlap(int x, int y) {

    b2Manifold mani;
    mani.pointCount = 0;
    //pos de Mario.
    b2Rot rotA(0);
    //Coordinate element A
    b2Vec2 vecA(x, y);
    b2Transform tranA(vecA, rotA);
    //creo el shape de mario.
    b2PolygonShape boxA;
    boxA.SetAsBox(this->objWidth / 2, this->objHeight / 2);

    //GROUND
    b2Rot rotGround(0);
    b2Vec2 vecGround(this->windowUnitWidth / 2, this->windowUnitHeight);
    b2Transform tranGround(vecGround, rotGround);
    b2PolygonShape boxGround;
    boxGround.SetAsBox(this->windowUnitWidth / 2, (this->windowUnitHeight / 2)*0.05);
    //comparo
    b2CollidePolygons(&mani, &boxA, tranA, &boxGround, tranGround);
    if (mani.pointCount > 0) {
        return true;
    }
    //CEILING
    b2Rot rotCeiling(0);
    b2Vec2 vecCeiling(this->windowUnitWidth / 2, 0);
    b2Transform tranCeiling(vecCeiling, rotCeiling);
    b2PolygonShape boxCeiling;
    boxCeiling.SetAsBox(this->windowUnitWidth / 2, 2);
    b2CollidePolygons(&mani, &boxA, tranA, &boxCeiling, tranCeiling);

    if (mani.pointCount > 0) {
        return true;
    }
    //LEFTWALL
    b2Rot rotLeftWall(0);
    b2Vec2 vecLeftWall(0, this->windowUnitHeight / 2);
    b2Transform tranLeftWall(vecLeftWall, rotLeftWall);
    b2PolygonShape boxLeftWall;
    boxLeftWall.SetAsBox(2, this->windowUnitHeight / 2);
    b2CollidePolygons(&mani, &boxA, tranA, &boxLeftWall, tranLeftWall);
    if (mani.pointCount > 0) {
        return true;
    }
    //rightWall RIGHTWALL
    b2Rot rotRightWall(0);
    b2Vec2 vecRightWall(this->windowUnitWidth, this->windowUnitHeight / 2);
    b2Transform tranRightWall(vecRightWall, rotRightWall);
    b2PolygonShape boxRightWall;
    boxRightWall.SetAsBox(2, (this->windowUnitHeight / 2));
    //comparo
    b2CollidePolygons(&mani, &boxA, tranA, &boxRightWall, tranRightWall);
    if (mani.pointCount > 0) {
        return true;
    }
    return false;
}

void Character::actualizePosition() {
    b2Vec2 currentPos = (this->object->getPosition());
    this->dot->setPos(currentPos.x, currentPos.y);
}

float Character::getPosX() {
    this->actualizePosition();
    return this->dot->getPos()->x;
}

float Character::getPosInitialX() {
    Dot *dotito = new Dot(this->posInitial.x, this->posInitial.y);
    float x = dotito->dotWorldToPixels()->x;
    delete dotito;
    return x;
}

float Character::getPosInitialY() {
    Dot *dotito = new Dot(this->posInitial.x, this->posInitial.y);
    float y = dotito->dotWorldToPixels()->y;
    delete dotito;
    return y;
}

float Character::getPosY() {
    this->actualizePosition();
    return this->dot->getPos()->y;
}

void Character::die() {
    this->data.stateCharacter = DEAD;
    this->data.imageId = -1;
    this->dead = true;
    this->dying = true;
}

void Character::kill() {
    //    cout<<"ENTRA A DIEEEEEEEEEEEEEEEEEEEEElllllllllllllllllllllllll"<<endl;
    //    this->data.stateCharacter = DEAD;
    //    this->data.imageId = -1;    // no debe dibujarlo
    //    this->dead = true;
    //    this->dying = true;
}

void Character::stopKneeling() {
    counterKneel = 1;
    this->kneeling = false;
}

int Character::getState() {

    if (isJumping()) {
        return JUMPING;
    }
    if (isKneeling()) {
        this->resetFallingAndJumping();
        return KNEELING;
    }
    if (isFallingDown()) {
        return FALLING;
    }
    if (isWalking()) {
        this->resetFallingAndJumping();
        return WALKING;
    }
    if (isWatching()) {
        return WATCHING;
    } else {
        this->resetFallingAndJumping();
        return WAITING;
    }

}

bool Character::isJumping() {
    return this->jumping;
}

bool Character::isWalking() {
    return this->walking;
}

bool Character::isKneeling() {
    return this->kneeling;
}

void Character::stopWalking() {
    this->walking = false;
}

bool Character::isFallingDown() {

    float velY2;
    velY2 = this->object->getBody()->GetLinearVelocity().y;
    if (velY2 == 0) {
        return false;
    }

    this->fallingDown = true;

    if (wasJumping) {
        if (this->object->getBody()->GetLinearVelocity().y <= 0.05) {
            wasJumping = true;
        } else {
            wasJumping = false;
        }

        b2Fixture* fixt = this->object->getBody()->GetFixtureList();
        if (fixt->IsSensor()) {
            fixt = fixt->GetNext();
        }
        b2Filter filter = fixt->GetFilterData();
        filter.groupIndex = GROUPINDEXCHARACTER;
        fixt->SetFilterData(filter);

        return fallingDown;

    } else {

        b2Body* body = this->object->getBody();

        for (b2ContactEdge* contList = body->GetContactList(); contList; contList = contList->next) {
            b2Contact* cont = contList->contact;
            b2Fixture* fixtA = cont->GetFixtureA();
            b2Fixture* fixtB = cont->GetFixtureB();
            void* dataVoidA = fixtA->GetUserData();
            int data = *((int*) &dataVoidA);
            if (data == IS_FLOOR && fixtB->IsSensor() && (this->object->getBody()->GetLinearVelocity().y < 0.05)) {
                this->fallingDown = false;
            }
            void* dataVoidB = fixtB->GetUserData();
            data = *((int*) &dataVoidB);
            if (data == IS_FLOOR && fixtA->IsSensor() && (this->object->getBody()->GetLinearVelocity().y < 0.05)) {
                this->fallingDown = false;
            }
        }

        if (this->fallingDown) {
            b2Fixture* fixt = this->object->getBody()->GetFixtureList();
            if (fixt->IsSensor()) {
                fixt = fixt->GetNext();
            }
            b2Filter filter = fixt->GetFilterData();
            filter.groupIndex = GROUPINDEXCHARACTER;
            fixt->SetFilterData(filter);
        }
        return this->fallingDown;
    }
}

bool Character::isWalkingRight() {
    if (this->walking && this->directionRight) {
        return true;
    }
    return false;
}

bool Character::isWalkingLeft() {
    if (this->walking && !(this->directionRight)) {
        return true;
    }
    return false;
}

bool Character::isWatching() {
    return this->watching;
}

void Character::keepFallingDown() {
    this->currentVelY = this->object->getBody()->GetLinearVelocity().y;
    this->actualizePosition();
}

void Character::jumpRight() {

    b2Body* body = this->object->getBody();

    b2Fixture* fixt = body->GetFixtureList();
    if (fixt->IsSensor()) {
        fixt = fixt->GetNext();
    }
    b2Filter filter = fixt->GetFilterData();
    filter.groupIndex = filter.groupIndex | GROUPINDEXPLATFORM;
    fixt->SetFilterData(filter);

    b2Vec2 velocity((0.7f) * PRINCIPAL_SCALE, (-10.2f) * PRINCIPAL_SCALE);
    body->SetLinearVelocity(velocity);
}

void Character::jumpLeft() {

    b2Body* body = this->object->getBody();

    b2Fixture* fixt = body->GetFixtureList();
    if (fixt->IsSensor()) {
        fixt = fixt->GetNext();
    }
    b2Filter filter = fixt->GetFilterData();
    filter.groupIndex = filter.groupIndex | GROUPINDEXPLATFORM;
    fixt->SetFilterData(filter);

    b2Vec2 velocity((-0.7f) * PRINCIPAL_SCALE, (-10.2f) * PRINCIPAL_SCALE);
    body->SetLinearVelocity(velocity);
}

void Character::moveRight(float velocityX, float velocityY) {

    b2Body* body = this->object->getBody();
    b2Vec2 velocity(velocityX*PRINCIPAL_SCALE, velocityY);
    body->SetLinearVelocity(velocity);
}

void Character::moveLeft(float velocityX, float velocityY) {

    b2Body* body = this->object->getBody();
    b2Vec2 velocity(-velocityX*PRINCIPAL_SCALE, velocityY);
    body->SetLinearVelocity(velocity);
}

void Character::fallRight() {
    this->directionRight = true;
    if (this->canFallRight) {
        //    if ((this->canFallRight) && (this->currentVelY > 4.0f)) {
        this->moveRight(this->constFall, this->currentVelY++);
        this->canFallRight = false;
        this->canFallLeft = true;
    }
}

void Character::fallLeft() {
    this->directionRight = false;
    if (this->canFallLeft) {
        //    if ((this->canFallLeft) && (this->currentVelY > 4.0f)) {
        this->moveLeft(this->constFall, this->currentVelY++);
        this->canFallRight = true;
        this->canFallLeft = false;
    }
}

void Character::jumpingRight() {
    if (this->directionRight) {
        if (this->canJumpRight) {
            this->moveRight(this->constJump, this->currentVelY--);
            this->canJumpRight = false;
        }
    }
}

void Character::jumpingLeft() {
    if (!this->directionRight) {
        if (this->canJumpLeft) {
            this->moveLeft(this->constJump, this->currentVelY--);
            this->canJumpLeft = false;
        }
    }
}

void Character::resetFallingAndJumping() {
    this->canJumpLeft = true;
    this->canJumpRight = true;
    this->canFallRight = true;
    this->canFallLeft = true;
}

void Character::kneel() {

    this->walking = false;
    this->actualizePosition();
    beginning = false;
    counterKneel++;
    if (counterKneel >= 2) {
        kneeling = true;
        counterKneel++;
    }
}

void Character::keepKneeling() {
    this->actualizePosition();
    counterKneel++;
}

void Character::jump() {

    this->beginning = false;
    counterJump++;
    jumping = true;
    kneeling = false;
    counterKneel = 1;

    if (this->trapped) {
        //        b2Vec2 pos = this->crazyBallKidnapper->GetPosition();
        //        this->changePosition(pos.x, pos.y);
        this->trapped = false;
    }

    this->actualizePosition();
    counterJump++;

}

void Character::changePosition(float x, float y) {
    Dot *dot = new Dot(x, y);
    dot->dotPixelsToWorld();
    b2Vec2* pos = dot->getPos();
    this->object->getBody()->SetTransform(*pos, 0);
    delete dot;
}

void Character::keepJumping() {
    this->currentVelY = this->object->getBody()->GetLinearVelocity().y;
    if (directionRight) {
        this->actualizePosition();
        switch (this->counterJump) {
            case (3):
                counterJump++;
                break;
            case (4):
                counterJump++;
                break;
            case (5):
                counterJump++;
                break;
            case (6):
                counterJump++;
                break;
            case (7):
                this->jumpRight();
                counterJump++;
                break;
            case (8):
                this->jumpRight();
                counterJump++;
                break;
            case (9):
                float velY;
                velY = this->object->getBody()->GetLinearVelocity().y;
                if (velY > -2) {
                    this->counterJump = 1;
                    this->jumping = false;
                    this->wasJumping = true;
                    this->canJumpLeft = true;
                    this->canJumpRight = true;
                }
                break;
            default:
                float velY2;
                velY2 = this->object->getBody()->GetLinearVelocity().y;
                if (velY2 == 0) {
                    this->counterJump = 1;
                    this->jumping = false;
                    this->wasJumping = true;
                    this->canJumpLeft = true;
                    this->canJumpRight = true;
                }
                break;
        }
    } else {
        this->actualizePosition();
        switch (this->counterJump) {
            case (3):
                counterJump++;
                break;
            case (4):
                counterJump++;
                break;
            case (5):
                counterJump++;
                break;
            case (6):
                counterJump++;
                break;
            case (7):
                this->jumpLeft();
                counterJump++;
                break;
            case (8):
                this->jumpLeft();
                counterJump++;
                break;
            case (9):
                float velY2;
                velY2 = this->object->getBody()->GetLinearVelocity().y;
                if (velY2 > -2) {
                    this->counterJump = 1;
                    this->jumping = false;
                    this->wasJumping = true;
                    this->canJumpLeft = true;
                    this->canJumpRight = true;
                }
                break;
            default:
                float velY;
                velY = this->object->getBody()->GetLinearVelocity().y;
                if (velY == 0) {
                    this->counterJump = 1;
                    this->jumping = false;
                    this->wasJumping = true;
                    this->canJumpLeft = true;
                    this->canJumpRight = true;
                }
                break;
        }
    }
}

void Character::wait() {
    this->walking = false;
    kneeling = false;
    counterKneel = 1;
    this->actualizePosition();
    b2Vec2 vec = this->object->getPosition();
    if (this->isFallingDown()) {
        this->keepFallingDown();
    } else {
        if (counterWait > 8) {
            velocityWalkRight = 0.0;
            velocityWalkLeft = 0.0;
        } else {
            counterWait++;

        }
        if (counterWait > 100) {
            counterWait = 9;
        }
    }
}

void Character::keepWalking() {


    if (this->walkingFaster) {
        this->nowVel = std::chrono::system_clock::now();
        int elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>
                (this->nowVel - this->startPlusVel).count();
        if (elapsed_seconds > this->plusVelTime) {
            this->walkingFaster = false;
            this->maxVelocity = this->maxVelocityStandard;
        }
    }

    if (this->directionRight) {
        if (velocityWalkRight < maxVelocity) {
            velocityWalkRight = velocityWalkRight + deltaVelocity;
        }
        this->moveRight(velocityWalkRight, 0.0f);
        this->actualizePosition();
    } else {
        if (velocityWalkLeft < maxVelocity) {
            velocityWalkLeft = velocityWalkLeft + deltaVelocity;
        }
        this->moveLeft(velocityWalkLeft, 0.0f);
        this->actualizePosition();
    }
}

void Character::walkRight() {
    kneeling = false;
    counterKneel = 1;
    this->moveRight(velocityWalkRight, 0.0f);
    this->actualizePosition();
    counterWait = 1;
    this->beginning = false;
    this->directionRight = true;
    this->walking = true;
}

void Character::walkLeft() {
    kneeling = false;
    counterKneel = 1;
    this->moveLeft(velocityWalkLeft, 0.0f);
    this->actualizePosition();
    counterWait = 1;
    this->beginning = false;
    this->walking = true;
    this->directionRight = false;
}

void Character::updatePosition() {
    this->data.x = this->getPosX();
    this->data.y = this->getPosY();
}

void Character::updateState() {
    this->data.stateCharacter = this->getState();
    this->data.direction = this->directionRight;
}

void Character::updateRotation() {
    // no tiene rotacion
}

void Character::updateEvent(struct Event e) {
    this->data.event = e;
}

void Character::updateData() {
    if (!dead) {
        this->updatePosition();

        this->updateState();

        this->data.lifes = this->lifes;
        this->data.score = this->score;
    }
}

void Character::setUbicDyn(int id) {
    this->data.ubicDyn = id;
}

int Character::getUbicDyn() {
    return this->data.ubicDyn;
}

void Character::setCharacterId(int id) {
    this->data.idCharacter = id;
}

struct ObjectInit Character::getData() {
    this->updateData();
    this->data.level = 0;
    return this->data;
}

int Character::getLifes() {
    return this->lifes;
}

int Character::getScore() {
    return this->score;
}

bool Character::getAreEquals() {
    if (this->avisarleATodos) {
        this->contAvisarleATodos--;
        if (this->contAvisarleATodos < -4) {
            this->avisarleATodos = false;
            this->contAvisarleATodos = 1;
        }
        return false;
    }

    if (this->equals && (this->lastState == this->data.stateCharacter)) {
        //        this->lastState = this->data.stateCharacter; // actualizo para siguiente vuelta
        return true;
    } else {
        this->lastState = this->data.stateCharacter; // actualizo para siguiente vuelta
        return false;
    }

}

b2Body* Character::getBody() {
    return this->object->getBody();
}

void Character::checkChanges() {
    b2Vec2 pos = this->object->getPosition();

    if (this->counterReborn > 0) {
        if (this->counterReborn % 2 == 0) { // si es par
            this->data.imageId = -1;
        } else {
            this->data.imageId = 0;
        }

        this->counterReborn = this->counterReborn - 1;

        if (this->counterReborn == 0) {
            b2Fixture* fixt = this->object->getBody()->GetFixtureList();
            if (fixt->IsSensor()) {
                fixt = fixt->GetNext();
            }
            b2Filter filter = fixt->GetFilterData();
            filter.groupIndex = GROUPINDEXCHARACTER;
            fixt->SetFilterData(filter);
            this->avisarleATodos = true;
            this->contAvisarleATodos = 1;
        }
    }

    if (this->dying) {
        //        this->nd++;
        //        if (nd > 10) {
        //            this->nd = 0;
        this->dying = false;
        //        }
        this->equals = false;

    } else if (this->dead) {
        //        cout << "CHARACTER " << this->getData().idCharacter << " MUERTOOOOOOOOOOOOOO"<<endl;
        this->equals = true;

    } else if (this->data.x == pos.x && this->data.y == pos.y) {
        //        cout << "CHARACTER " << this->getData().idCharacter << " IDEM POSSSSSSSSSSSSSSSSSSS"<<endl;
        this->equals = true;
    } else {
        this->equals = false;
    }
}

bool Character::isInContactBonus() {

    b2Body* body = this->object->getBody();

    for (b2ContactEdge* contList = body->GetContactList(); contList; contList = contList->next) {
        b2Contact* cont = contList->contact;
        b2Fixture* fixtA = cont->GetFixtureA();
        b2Fixture* fixtB = cont->GetFixtureB();

        void* dataVoidA = fixtA->GetUserData();
        int dataA = *((int*) &dataVoidA);

        if (dataA == IS_BONUS_FLASH || dataA == IS_BONUS_LIFE) {
            switch (dataA) {
                case IS_BONUS_FLASH:
                    this->walkFaster();
                    break;
                case IS_BONUS_LIFE:
                    this->lifes = this->lifes + 1;
                    break;
            }
            fixtA->GetBody()->SetUserData((void*) TO_DELETE);

            this->score = this->score + POINTSBONUS;

            return true;
        }

        void* dataVoidB = fixtB->GetUserData();
        int dataB = *((int*) &dataVoidB);

        if (dataB == IS_BONUS_FLASH || dataB == IS_BONUS_LIFE) {
            switch (dataB) {
                case IS_BONUS_FLASH:
                    this->walkFaster();
                    break;
                case IS_BONUS_LIFE:
                    this->lifes = this->lifes + 1;
                    break;
            }
            fixtB->GetBody()->SetUserData((void*) TO_DELETE);

            this->score = this->score + POINTSBONUS;

            return true;
        }
    }
    return false;
}

bool Character::isInContactEnemy() {

    if (this->counterReborn > 0) {
        return false;
    }

    b2Body* body = this->object->getBody();

    for (b2ContactEdge* contList = body->GetContactList(); contList; contList = contList->next) {
        b2Contact* cont = contList->contact;
        b2Fixture* fixtA = cont->GetFixtureA();
        b2Fixture* fixtB = cont->GetFixtureB();

        void* dataVoidA = fixtA->GetUserData();
        int dataA = *((int*) &dataVoidA);

        if (((dataA == IS_ENEMY) && (fixtA->GetFilterData().groupIndex == GROUPINDEXENEMY)) || dataA == IS_FIRE || dataA == THE_BOSS) {
            this->lifes = this->lifes - 1;
            if (this->lifes < 0) {
                if (!(this->watching)) {
                    Dot *dot = new Dot(-100, -100);
                    dot->dotPixelsToWorld();
                    b2Vec2* pos = dot->getPos();
                    this->object->getBody()->SetTransform(*pos, 0);
                    delete dot;
                    this->object->getBody()->SetType(b2_staticBody);
                    this->avisarleATodos = true;
                    this->contAvisarleATodos = 1;
                }
                this->watching = true;
            } else {
                this->changeToPosInitial();
                this->stopWalking();
                this->counterReborn = 201; // tiene que ser impar o no lo dibuja al final
                this->avisarleATodos = true;
                this->contAvisarleATodos = 1;
            }
            return true;
        }

        void* dataVoidB = fixtB->GetUserData();
        int dataB = *((int*) &dataVoidB);

        if (((dataB == IS_ENEMY) && (fixtB->GetFilterData().groupIndex == GROUPINDEXENEMY)) || dataB == IS_FIRE || dataB == THE_BOSS) {
            this->lifes = this->lifes - 1;
            if (this->lifes < 0) {
                if (!(this->watching)) {
                    Dot *dot = new Dot(-100, -100);
                    dot->dotPixelsToWorld();
                    b2Vec2* pos = dot->getPos();
                    this->object->getBody()->SetTransform(*pos, 0);
                    delete dot;
                    this->object->getBody()->SetType(b2_staticBody);
                    this->avisarleATodos = true;
                    this->contAvisarleATodos = 1;
                }
                this->watching = true;
            } else {

                this->changeToPosInitial();
                this->stopWalking();
                this->counterReborn = 201; // tiene que ser impar o no lo dibuja al final
                this->avisarleATodos = true;
                this->contAvisarleATodos = 1;
            }
            return true;
        }
    }

    return false;
}

bool Character::isInContactSnowBallEnemy() {
    // si el character esta en contacto con un enemigo atrapado del todo
    b2Body* body = this->object->getBody();

    for (b2ContactEdge* contList = body->GetContactList(); contList; contList = contList->next) {
        b2Contact* cont = contList->contact;
        b2Fixture* fixtA = cont->GetFixtureA();
        b2Fixture* fixtB = cont->GetFixtureB();

        void* dataVoidA = fixtA->GetUserData();
        int dataA = *((int*) &dataVoidA);

        if (dataA == IS_ENEMY_CAUGHT) {
            // si estaba en contacto le aviso al enemy que debe ser golpeado
            fixtA->GetBody()->SetUserData((void*) TO_KICK);
            this->score = this->score + POINTSKILLENEMY;
            return true;
        }

        void* dataVoidB = fixtB->GetUserData();
        int dataB = *((int*) &dataVoidB);

        if (dataB == IS_ENEMY_CAUGHT) {
            // si estaba en contacto le aviso al enemy que debe ser golpeado
            fixtB->GetBody()->SetUserData((void*) TO_KICK);
            this->score = this->score + POINTSKILLENEMY;
            return true;
        }
    }

    return false;
}

bool Character::isInContactCrazyBall() {
    //    b2Body* body = this->getBody();
    //    for (b2ContactEdge* contList = body->GetContactList(); contList; contList = contList->next) {
    //        b2Contact* cont = contList->contact;
    //        b2Fixture* fixtA = cont->GetFixtureA();
    //        b2Fixture* fixtB = cont->GetFixtureB();
    //        void* dataVoidA = fixtA->GetUserData();
    //        void* dataVoidB = fixtB->GetUserData();
    //
    //        int dataA = *((int*) &dataVoidA);
    //        int dataB = *((int*) &dataVoidB);
    //
    //        if (dataA == IS_CRAZY_BALL) {
    //            //            cout << "characterrrrrrrrrrrrrrrrrr in CONTACTTTTTTTTTTTTTTTT" << endl;
    //            //            this->crazyBallKidnapper = fixtA->GetBody();
    //            this->trapped = true;
    //            return true;
    //        }
    //
    //        if (dataB == IS_CRAZY_BALL) {
    //            //            cout << "characterrrrrrrrrrrrrrrrrr in CONTACTTTTTTTTTTTTTTTT" << endl;
    //            //            this->crazyBallKidnapper = fixtB->GetBody();
    //            this->trapped = true;
    //            return true;
    //        }
    //    }
    return false;
}

void Character::changeToPosInitial() {
    b2Body* body = this->object->getBody();

    //    cout << "Regreso a pos inicial: ( " << this->posInitial.x << " , " << this->posInitial.y << " )" << endl;
    body->SetTransform(this->posInitial, 0);

    b2Fixture* fixt = body->GetFixtureList();
    if (fixt->IsSensor()) {
        fixt = fixt->GetNext();
    }
    b2Filter filter = fixt->GetFilterData();
    filter.groupIndex = filter.groupIndex | GROUPINDEXENEMY;
    fixt->SetFilterData(filter);
    
    this->maxVelocity=this->maxVelocityStandard;

}

void Character::walkFaster() {
    this->walkingFaster = true;
    this->maxVelocity = this->maxVelocityPlus;
    this->startPlusVel = std::chrono::system_clock::now();
}

void Character::setWaiting() {
    if (!this->watching) {
        this->canFallLeft = true;
        this->canFallRight = true;
        this->canJumpLeft = true;
        this->canJumpRight = true;
        this->jumping = false;
        this->kneeling = false;
        this->walking = false;
        this->fallingDown = false;
        this->wasJumping = false;
    }
}

void Character::notBeInvisible() {
    this->avisarleATodos = true;
    this->contAvisarleATodos = 1;
}

//shoot

SnowBall * Character::shoot() {
    //#NOTA: Cambiar el harcode de mass y escala. Ultimos dos parametros de getBUllet
    //    int scale, float mass, int idImage   
    int dire;
    if (this->directionRight) {
        dire = 1;
    } else {
        dire = -1;
    }
    SnowBall * snowBall = this->weapon->getBullet(this->getPosX(), this->getPosY(), dire); //disparo una bala al mundo             
    return snowBall;
}

Character::~Character() {
    delete this->object;
    delete this->dot;
}